package priv.wangy.micro.common.utils.file.impl;

import org.apache.commons.io.FilenameUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import priv.wangy.micro.common.utils.file.FileType;
import priv.wangy.micro.common.utils.file.IFileTypeUtil;
import priv.wangy.micro.common.utils.HexUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;

/**
 * @author 张嘉琪
 * @since 2023-04-24
 */
public class BaseTypeUtil implements IFileTypeUtil {

    private static final IFileTypeUtil INSTANCE = new BaseTypeUtil();

    /**
     * 判断文件是否有效
     *
     * @param file 文件
     * @return 文件有效时返回true
     */
    public static boolean chkFileVerify(MultipartFile file) {
        return !file.isEmpty() && StringUtils.hasLength(file.getOriginalFilename()) && file.getSize() > 16;
    }

    /**
     * 检查文件魔数
     * 判断文件魔术数字是否与文件扩展名匹配
     *
     * @param file 文件
     * @param type 文件类型
     * @return 当文件魔数与文件类型【不匹配】时，返回true
     * @throws IOException IO异常
     */
    public static boolean chkMagicNumber(MultipartFile file, FileType type) throws IOException {
        InputStream is = file.getInputStream();
        byte[] bytes = new byte[16];
        int r = is.read(bytes, 0, 16);
        String magicNumber = HexUtils.bytesToHex(bytes).toUpperCase(Locale.ROOT);
        is.close();
        return !magicNumber.startsWith(type.getMagicNumber());
    }

    @Override
    public boolean typeVerify(MultipartFile file) {
        try {
            if (chkFileVerify(file)) {
                /*
                判断文件扩展名是否为常见图片类型
                 */
                String extension = FilenameUtils.getExtension(file.getOriginalFilename());
                FileType type = FileType.getByExtension(extension);
                if (Objects.isNull(type)) {
                    return false;
                }
                /*
                判断文件魔术数字是否与文件扩展名匹配
                 */
                if (chkMagicNumber(file, type)) {
                    return false;
                }
                /*
                根据文件类型分发校验
                 */
                if (Arrays.asList(FileType.getImgFileTypes()).contains(type)) {
                    return ImgTypeUtil.getInstance().advancedTypeVerify(file);
                }
                return true;
            }
            return false;
        } catch (IOException e) {
            return false;
        }
    }

    @Override
    public boolean advancedTypeVerify(MultipartFile file) {
        return true;
    }

    public static IFileTypeUtil getInstance() {
        return INSTANCE;
    }
}
